﻿// Copyright (c) Microsoft Corporation
//
// All rights reserved. 
//
// Licensed under the Apache License, Version 2.0 (the ""License""); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING 
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY 
// OR NON-INFRINGEMENT. 
//
// See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TED.WindowsAzure.Unplugged.Mobile.Extensions;
using TED.WindowsAzure.Unplugged.Mobile.Folder;
using TED.WindowsAzure.Unplugged.Mobile.Storage;
using TED.WindowsAzure.Unplugged.Mobile.Sync.Events;
using TED.WindowsAzure.Unplugged.Mobile.Sync.File;
using TED.WindowsAzure.Unplugged.Mobile.Sync.Storage;
using Windows.Storage;
using Windows.Storage.Streams;

namespace TED.WindowsAzure.Unplugged.Mobile.Sync.Folder
{
    public class SyncFolder : ISyncFolder
    {
        private readonly RemoteFolder _remoteFolder;
        private readonly SyncEnabledStorage _syncEnabledStorage;

        internal SyncFolder(string folderName, SyncEnabledStorage syncEnabledStorage,
            IRemoteFileStorage remoteFileStorage)
        {
            FolderName = folderName;
            _syncEnabledStorage = syncEnabledStorage;
            _remoteFolder = new RemoteFolder(remoteFileStorage, folderName);

            InitEvents();
        }

        public string FolderName { get; private set; }

        public async Task<IEnumerable<ISyncFile>> ReadAsync()
        {
            return await _syncEnabledStorage.ReadAsync(this, _remoteFolder);
        }

        public async Task<IRandomAccessStream> OpenReadAsync(ISyncFile instance)
        {
            return await _syncEnabledStorage.OpenReadAsync(instance);
        }

        public async Task<IRandomAccessStream> OpenWriteAsync(ISyncFile instance)
        {
            return await _syncEnabledStorage.OpenWriteAsync(instance);
        }

        public async Task<IStorageFile> GetInternalStorageFile(ISyncFile instance)
        {
            return await _syncEnabledStorage.GetInternalStorageFile(instance);
        }

        public async Task<ISyncFile> LookupAsync(int id)
        {
            return await _syncEnabledStorage.LookupAsync(id, this, _remoteFolder);
        }

        public async Task<ISyncFile> LookupAsync(string name)
        {
            return await _syncEnabledStorage.LookupAsync(name, this, _remoteFolder);
        }

        /// <summary>
        ///     Creates a new file in the folder
        /// </summary>
        /// <param name="fileName">The desired name of the file to create</param>
        /// <returns>When this method completes, it returns the new file as ISyncFile</returns>
        public async Task<ISyncFile> CreateFileAsync(string fileName)
        {
            return await _syncEnabledStorage.CreateFileAsync(fileName, this, _remoteFolder);
        }

        /// <summary>
        ///     Push changes to remote server
        /// </summary>
        /// <returns></returns>
        public async Task PushAsync()
        {
            await _syncEnabledStorage.PushAsync(this, _remoteFolder);
        }

        /// <summary>
        ///     Pull changes from remote server
        /// </summary>
        /// <returns></returns>
        public async Task PullAsync()
        {
            await _syncEnabledStorage.PullAsync(this, _remoteFolder);
        }

        /// <summary>
        ///     Delete all contents form the folder
        /// </summary>
        /// <returns></returns>
        public async Task TruncateAsync()
        {
            await _syncEnabledStorage.TruncateAsync(this);
        }

        /// <summary>
        /// </summary>
        /// <param name="instance"></param>
        /// <param name="source"></param>
        /// <returns></returns>
        public async Task InsertAndCommitAsync(ISyncFile instance, IRandomAccessStream source)
        {
            await _syncEnabledStorage.InsertAndCommitAsync(instance, source, _remoteFolder);
        }

        public async Task UpdateAndCommitAsync(ISyncFile instance, IRandomAccessStream source)
        {
            await _syncEnabledStorage.UpdateAndCommitAsync(instance, source, _remoteFolder);
        }

        public async Task DeleteAsync(ISyncFile instance)
        {
            await _syncEnabledStorage.DeleteAsync(instance, _remoteFolder);
        }

        public async Task FlushAsync()
        {
            await _syncEnabledStorage.FlushAsync(this);
        }

        public async Task CommitAsync(ISyncFile instance)
        {
            await _syncEnabledStorage.CommitAsync(instance);
        }

        public async Task CancelAsync()
        {
            await _syncEnabledStorage.CancelAsync(this);
        }

        public async Task UndoAsync(ISyncFile instance)
        {
            await _syncEnabledStorage.UndoAsync(instance);
        }

        #region Events

        public event EventHandler<SyncStartedEventArgs> PullStarted;

        public event EventHandler<SyncProgressEventArgs> PullProgressChanged;

        public event EventHandler<SyncCompletedEventArgs> PullCompleted;

        public event EventHandler<SyncStartedEventArgs> PushStarted;

        public event EventHandler<SyncProgressEventArgs> PushProgressChanged;

        public event EventHandler<SyncCompletedEventArgs> PushCompleted;

        public event EventHandler<SyncListBuiltEventArgs> SyncListBuilt;

        public event EventHandler<SyncConnectionEventArgs> SyncConnection;

        protected virtual void OnPullStarted(SyncStartedEventArgs e)
        {
            if (PullStarted != null)
            {
                UIDispatcher.BeginExecute(() => PullStarted(this, e));
            }
        }

        protected virtual void OnPullProgressChanged(SyncProgressEventArgs e)
        {
            if (PullProgressChanged != null)
            {
                UIDispatcher.BeginExecute(() => PullProgressChanged(this, e));
            }
        }

        protected virtual void OnPullCompleted(SyncCompletedEventArgs e)
        {
            if (PullCompleted != null)
                UIDispatcher.BeginExecute(() => PullCompleted(this, e));
        }

        protected virtual void OnPushStarted(SyncStartedEventArgs e)
        {
            if (PushStarted != null)
                UIDispatcher.BeginExecute(() => PushStarted(this, e));
        }

        protected virtual void OnPushProgressChanged(SyncProgressEventArgs e)
        {
            if (PushProgressChanged != null)
                UIDispatcher.BeginExecute(() => PushProgressChanged(this, e));
        }

        protected virtual void OnPushCompleted(SyncCompletedEventArgs e)
        {
            if (PushCompleted != null)
                UIDispatcher.BeginExecute(() => PushCompleted(this, e));
        }

        protected virtual void OnSyncListBuilt(SyncListBuiltEventArgs e)
        {
            if (SyncListBuilt != null)
                UIDispatcher.BeginExecute(() => SyncListBuilt(this, e));
        }

        protected virtual void OnSyncConnection(SyncConnectionEventArgs e)
        {
            if (SyncConnection != null)
                UIDispatcher.BeginExecute(() => SyncConnection(this, e));
        }

        #endregion

        private void InitEvents()
        {
            _syncEnabledStorage.PullStarted += (sender, args) =>
            {
                if (args.SyncFolder == this)
                    OnPullStarted(args);
            };
            _syncEnabledStorage.PullCompleted += (sender, args) =>
            {
                if (args.SyncFolder == this)
                    OnPullCompleted(args);
            };
            _syncEnabledStorage.SyncListBuilt += (sender, args) =>
            {
                if (args.SyncFolder == this)
                    OnSyncListBuilt(args);
            };
            _syncEnabledStorage.PullProgressChanged += (sender, args) =>
            {
                if (args.SyncFolder == this)
                    OnPullProgressChanged(args);
            };

            _syncEnabledStorage.PushStarted += (sender, args) =>
            {
                if (args.SyncFolder == this)
                    OnPushStarted(args);
            };
            _syncEnabledStorage.PushCompleted += (sender, args) =>
            {
                if (args.SyncFolder == this)
                    OnPushCompleted(args);
            };
            _syncEnabledStorage.PushProgressChanged += (sender, args) =>
            {
                if (args.SyncFolder == this)
                    OnPushProgressChanged(args);
            };
            _syncEnabledStorage.SyncConnection += (sender, args) =>
            {
                if (args.SyncFolder == this)
                    OnSyncConnection(args);
            };
        }
    }
}